package calendar;

import calendar.messages.*;
import edu.gmu.messages.EndPoint;
import edu.gmu.middleware.CallbackStub;
import edu.gmu.middleware.RemoteStub;
import edu.gmu.middleware.Message;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;

public class CalendarStub implements CalendarObjInt
{
    private RemoteStub           stub = null;
    private CallbackStub callbackStub = null;
    private EndPoint endpoint         = null;
    
    /**
     * Creates a new CalendarStub with specified params.
     */
    public CalendarStub( EndPoint endpoint ) throws IOException
    {
        this.endpoint     = endpoint;
        
        this.stub         = new RemoteStub( endpoint.address,
                                            endpoint.port,
                                            endpoint.port,
                                            endpoint.address );
        

        this.stub.register(Topic.USER_RESPONSE,          UserResponse.class);
        this.stub.register(Topic.ISCONNECTED_RESPONSE,   IsconnectedResponse.class);
        this.stub.register(Topic.CLEAR_MEMBERS_RESPONSE, ClearMembersResponse.class);
        this.stub.register(Topic.SCHEDULE_RESPONSE,      ScheduleResponse.class);
        this.stub.register(Topic.RETRIEVE_RESPONSE,      RetrieveResponse.class);
        this.stub.register(Topic.ALIVE_RESPONSE,         AliveResponse.class);
        this.stub.register(Topic.LOCK_RESPONSE,          LockResponse.class);
        this.stub.register(Topic.UNLOCK_RESPONSE,        UnlockResponse.class);
        this.stub.register(Topic.UPDATE_RESPONSE,        UpdateResponse.class);
    }
    
    public EndPoint getEndPoint()
    {
        return this.endpoint;
    }
    
    /**
     * Stops both the normal and callback stubs.
     */
    public void stop()
    {
        if(this.stub != null) this.stub.stop();
        if( this.callbackStub != null ) this.callbackStub.stop();
        //System.out.println( "CalendarStub: callbackStub.isConnected()=" + callbackStub.isConnected());
    }
    
    //------------------------------------------------------------------------//
    // Callback stuff
    //------------------------------------------------------------------------//
    public void registerCallback( final CallbackInt callbackInt ) throws IOException
    {
        EndPoint callbackEndpoint = new EndPoint();
        callbackEndpoint.address = this.endpoint.address;
        callbackEndpoint.port = this.endpoint.port + 1;
        // Lazy init
        if( this.callbackStub == null )
        {
            this.callbackStub = new CallbackStub( callbackEndpoint );
        }
        
        edu.gmu.middleware.Callback eventCallback = new edu.gmu.middleware.Callback()
        {
            public void execute( Message message )
            {
                NotifyEvent evt = (NotifyEvent)message;
                try
                {
                    callbackInt.notifyClientEvent(evt.event, evt.appt);
                }
                catch(IOException ioe)
                {
                    // will not happen in this context - no more io
                }
            }
        };
        this.callbackStub.register(Topic.NOTIFY_EVENT, NotifyEvent.class, eventCallback);
        
        edu.gmu.middleware.Callback userCallback = new edu.gmu.middleware.Callback()
        {
            public void execute( Message message )
            {
                NotifyUser evt = (NotifyUser)message;
                try
                {
                    callbackInt.notifyClientUser(evt.user, evt.users);
                }
                catch(IOException ioe)
                {
                    // will not happen in this context - no more io
                }
            }
        };
        this.callbackStub.register(Topic.NOTIFY_USER, NotifyUser.class, userCallback);

        edu.gmu.middleware.Callback reconnectCallback = new edu.gmu.middleware.Callback()
        {
            public void execute( Message message )
            {
                ReconnectRequest evt = (ReconnectRequest)message;
                try
                {
                  callbackInt.reconnect();
                }
                catch(IOException ioe)
                {
                    // will not happen in this context - no more io
                }
            }
        };
        this.callbackStub.register(Topic.RECONNECT_CLIENT, ReconnectRequest.class, reconnectCallback);
    }
    
    public void unregisterCallback( )
    {
        if( this.callbackStub != null )
        {
            this.callbackStub.unregister(Topic.NOTIFY_EVENT);
            this.callbackStub.unregister(Topic.NOTIFY_USER);
            this.callbackStub.unregister(Topic.RECONNECT_CLIENT);
        }
    }
    //------------------------------------------------------------------------//

    public ArrayList retrieveEvents(User user, Date start, Date end) throws IOException
    {
        RetrieveRequest r = new RetrieveRequest();
        r.user   = user;
        r.start  = start;
        r.end    = end;
        Message message = this.stub.execute(Topic.RETRIEVE_REQUEST, r);
        RetrieveResponse response = (RetrieveResponse)message;
        return response.events;
    }

    public ArrayList scheduleEvent(ArrayList users, Event newEvent, Event oldEvent, boolean addToThis) throws IOException
    {
        ScheduleRequest r = new ScheduleRequest();
        r.users     = users;
        r.newEvent  = newEvent;
        r.oldEvent  = oldEvent;
        r.addToThis = addToThis;
        Message message = this.stub.execute(Topic.SCHEDULE_REQUEST, r);
        ScheduleResponse response = (ScheduleResponse)message;
        return response.users;
    }

    public void updateEventUsers( ArrayList users, Event event ) throws IOException
    {
      UpdateRequest u = new UpdateRequest();
      u.users = users;
      u.event = event;
      Message message = this.stub.execute( Topic.UPDATE_REQUEST, u );
      UpdateResponse response = (UpdateResponse)message;
      return;
    }

    public char getUserId() throws IOException
    {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public User getUser() throws IOException
    {
        UserRequest request = new UserRequest();
        Message message = this.stub.execute(Topic.USER_REQUEST, request);
        UserResponse response = (UserResponse)message;
        return response.user;
    }

    public boolean isConnected() throws IOException
    {
        IsconnectedRequest request = new IsconnectedRequest();
        Message message = this.stub.execute(Topic.ISCONNECTED_REQUEST, request);
        IsconnectedResponse response = (IsconnectedResponse)message;
        return response.connected;
    }

    public void clearMembers() throws IOException
    {
        ClearMembersRequest request = new ClearMembersRequest();
        Message message = this.stub.execute(Topic.CLEAR_MEMBERS_REQUEST, request);
        ClearMembersResponse response = (ClearMembersResponse)message;
        return;
    }

  public void isAlive() throws IOException {
        AliveRequest request = new AliveRequest();
        Message message = this.stub.execute(Topic.ALIVE_REQUEST, request);
        AliveResponse response = (AliveResponse)message;
        return;
  }
  public boolean lock() throws IOException
  {
        LockRequest request = new LockRequest();
        Message message = this.stub.execute(Topic.LOCK_REQUEST, request);
        LockResponse response = (LockResponse)message;
        return response.locked;
  }
  public void unlock() throws IOException
  {
        UnlockRequest request = new UnlockRequest();
        Message message = this.stub.execute(Topic.UNLOCK_REQUEST, request);
        UnlockResponse response = (UnlockResponse)message;
        return;
  }
}
